package com.mic.yzzn.plc.common.ins.datastructure;
import java.io.Serializable;
import java.util.ArrayList;

import com.mic.yzzn.plc.common.toolUtils.PLCNumberTransform;

/**
 * 
 * Created by ASH on 16/3/7.
 */
public class PLCContactorNumber implements Serializable
{
    /** 序列化版本号 */
	private static final long serialVersionUID = -3168043071271068506L;
	/** 前三位BCD码 */
	private String BCDCode;
	/** 最后一位HEX码 */
    private char HEXCode;
	static private ArrayList<Character> hex_table;
	static private ArrayList<Character> re_hex_table;
    
    // 初始化方法
    public PLCContactorNumber()
    {	
        this("000", '0');
    }
    
    /**code: 200F {BCDCode:200; HEXCode:F}*/
    public PLCContactorNumber(String code)
    {
         this(code.substring(0, 3), code.charAt(3));
    }

    /**
     * 带参数的构造方法
     * @param BCDCode
     * @param HEXCode
     */
    public PLCContactorNumber(String BCDCode, char HEXCode) throws IllegalArgumentException
    {
    	// 如果列表为空则初始化
    	if (PLCContactorNumber.hex_table == null)
		{
        	ArrayList<Character> hex_table = new ArrayList<Character>();
        	ArrayList<Character> re_hex_table = new ArrayList<Character>();

        	int length = PLCNumberTransform.HEX_TABLE.length;
        	
        	for (int i = 0; i < length; ++i)
        	{
        		Character character = Character.valueOf(PLCNumberTransform.HEX_TABLE[i]);
        		Character reCharacter = Character.valueOf(PLCNumberTransform.HEX_TABLE[length - 1 - i]);
        		hex_table.add(character);
        		re_hex_table.add(reCharacter);
        	}
        	
        	PLCContactorNumber.hex_table = hex_table;
        	PLCContactorNumber.re_hex_table = re_hex_table;
		}
        setBCDCode(BCDCode);
        setHEXCode(HEXCode);
    }

    // Getter
    public char getHEXCode()
    {
        return HEXCode;
    }

    public String getBCDCode()
    {
        return BCDCode;
    }

    /**
     * BCDCode set方法
     * @param BCDCode
     * @throws IllegalArgumentException
     */
    public void setBCDCode(String BCDCode) throws IllegalArgumentException
    {
        // 检测参数范围
        int intValue = Integer.parseInt(BCDCode);
        if (intValue < 0 || intValue > 999)
        {
            throw new IllegalArgumentException("BCDCode is out of range(0 ~ 999)");
        }

        // 若不足三位则自动补足
        StringBuffer prefixBuffer = new StringBuffer();
        for (int i = BCDCode.length(); i < 3; ++i)
        {
            prefixBuffer.append("0");
        }
        prefixBuffer.append(BCDCode);

        this.BCDCode = prefixBuffer.toString();
    }

    /**
     * HEXCode set方法
     * @param HEXCode
     */
    public void setHEXCode(char HEXCode) throws IllegalArgumentException
    {
        // 检测参数的范围
        if (!((HEXCode >= 48 && HEXCode <= 57) || (HEXCode >= 65 && HEXCode <= 70)))
        {
            throw new IllegalArgumentException("HEXCode is out of range(0 ~ F)");
        }

        this.HEXCode = HEXCode;
    }

    @Override
    public String toString()
    {
        StringBuffer buffer = new StringBuffer();
        buffer.append(String.valueOf(this.BCDCode));
        buffer.append(this.HEXCode);

        return buffer.toString();
    }

    /**
     * 计算自己每一位的异或结果并返回
     */
    public int getXORByBit()
    {
        int result = 0;
        for (int i = 0; i < BCDCode.length(); ++i)
        {
            result ^= BCDCode.charAt(i);
        }
        result ^= HEXCode;

        return result;
    }
    
    /**
     * 返回两个触点编码的差值
     * @param smallNumber
     * @param largeNumber
     * @return
     * @throws IllegalArgumentException
     */
    public static int rangeOf(PLCContactorNumber smallNumber, PLCContactorNumber largeNumber) throws IllegalArgumentException
    {    	
    	int range = 0;
    	
    	int bcd_1 = Integer.parseInt(smallNumber.getBCDCode());
    	int bcd_2 = Integer.parseInt(largeNumber.getBCDCode());
    	
    	if (bcd_1 > bcd_2)
		{
			throw new IllegalArgumentException("smallNumber must less than largeNumber");
		}
    	
    	Character hex_1 = Character.valueOf(smallNumber.getHEXCode());
    	Character hex_2 = Character.valueOf(largeNumber.getHEXCode());
    	
    	int indexOfHex_1 = hex_table.indexOf(hex_1);
    	int indexOfHex_2 = hex_table.indexOf(hex_2);
    	
    	if (bcd_1 == bcd_2 && indexOfHex_2 < indexOfHex_1)
		{
			throw new IllegalArgumentException("smallNumber must less than largeNumber");
		}
    
    	// 计算BCD位的差值
    	int  bcdDiff = bcd_2 - bcd_1;
    	bcdDiff *= 16;
    	
    	// 计算HEX位的差值
    	int hexDiff = indexOfHex_2 - indexOfHex_1;
    	
    	// 计算出range
    	range = bcdDiff + hexDiff + 1;
    	
    	return range;
    }
    
    /**
     * 将触点编号加上一个数
     * @param addNumber
     */
    public void add(int addNumber) throws IllegalArgumentException
    {
    	// 判断是否小于零
    	boolean negative = (addNumber < 0);
    	
    	// 变成正数
    	if (negative)
		{
			addNumber *= -1;
		}
    	
    	int bcd = Integer.parseInt(getBCDCode());
    	Character hex = Character.valueOf(getHEXCode());
    	
    	int indexOfHex;
    	
    	// 如果小于零则反向取值
    	if (negative)
		{
			indexOfHex = PLCContactorNumber.re_hex_table.indexOf(hex);
		}
    	else 
    	{
    		indexOfHex = PLCContactorNumber.hex_table.indexOf(hex);
		}
    	
    	int carryOut = 0;
    	indexOfHex += addNumber;
    
    	carryOut = indexOfHex / 16;
    	indexOfHex -= carryOut * 16;
    	
    	if (negative)
		{
        	hex = PLCContactorNumber.re_hex_table.get(indexOfHex);
        	bcd -= carryOut;
		}
    	else
    	{
        	hex = PLCContactorNumber.hex_table.get(indexOfHex);
        	bcd += carryOut;
    	}
    	
    	setBCDCode(String.valueOf(bcd));
    	setHEXCode(hex.charValue());
    }
    
    public boolean isMax()
    {
    	return (getBCDCode().equals("999") && getHEXCode() == 'F');
    }
}
